// 导入依赖项
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:toast/toast.dart';

Dio dio = new Dio();

// 入口函数
void main() => runApp(MyApp());

// 自定义的 App 组件
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '颜值大师',
      theme: ThemeData(
        primarySwatch: Colors.purple,
      ),
      home: MyHomePage(title: '颜值大师'),
    );
  }
}

// 自定义的首屏页面组件
class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.

  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  // 用户通过摄像头或图片库选择的照片
  File _image;
  var faceInfo;
  bool isloading = false;
  Map genderMap = {'male': '男', 'female': '女'};
  Map expressionMap = {'none': '不笑', 'smile': '微笑', 'laugh': '大笑'};
  Map glassesMap = {'none': '无眼镜', 'common': '普通眼镜', 'sun': '墨镜'};
  Map emotionMap = {
    'angry': '愤怒',
    'disgust': '厌恶',
    'fear': '恐惧',
    'happy': '高兴',
    'sad': '伤心',
    'surprise': '惊讶',
    'neutral': '无情绪'
  };

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // 头部 AppBar 区域
      appBar: AppBar(
        title: Text(
          widget.title,
          style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
        ),
        centerTitle: true,
      ),
      // 中间页面主体区域
      body: renderBody(),
      // 底部浮动按钮区域
      floatingActionButton: ButtonBar(
        alignment: MainAxisAlignment.spaceAround,
        children: <Widget>[
          FloatingActionButton(
            onPressed: () {
              choosePic(ImageSource.camera);
            },
            tooltip: 'takephoto',
            child: Icon(Icons.photo_camera),
          ),
          FloatingActionButton(
            onPressed: () {
              choosePic(ImageSource.gallery);
            },
            tooltip: 'takepicture',
            child: Icon(Icons.photo_library),
          )
        ],
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }

  // 渲染页面主体区域
  Widget renderBody() {
    // 如果用户没有选择任何图片，则只渲染文本
    if (_image == null) {
      return Center(
        child: Text('暂无图片！'),
      );
    }
    // 在页面上渲染对应的图片
    return Stack(
      children: <Widget>[
        Image.file(
          _image,
          height: double.infinity,
          fit: BoxFit.cover,
        ),
        renderFaceInfo()
      ],
    );
  }

  // 渲染识别出来的人脸信息
  Widget renderFaceInfo() {
    if (faceInfo == null) {
      if (isloading) {
        return Center(child: CircularProgressIndicator());
      }
      return Text('');
    }
    return Center(
      child: Container(
        decoration: BoxDecoration(
            // 背景颜色
            color: Colors.white54,
            // 圆角
            borderRadius: BorderRadius.all(Radius.circular(5))),
        width: 300,
        height: 200,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: <Widget>[
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: <Widget>[
                Text('年龄：${faceInfo['age']}岁'),
                Text('性别：' + genderMap[faceInfo['gender']['type']]),
              ],
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: <Widget>[
                Text('颜值：${faceInfo['beauty']}分'),
                Text('表情：' + expressionMap[faceInfo['expression']['type']]),
              ],
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: <Widget>[
                Text('眼镜：' + glassesMap[faceInfo['glasses']['type']]),
                Text('情绪：' + emotionMap[faceInfo['emotion']['type']]),
              ],
            )
          ],
        ),
      ),
    );
  }

  // 点击按钮，选择图片
  void choosePic(source) async {
    // 得到选取的照片
    var image = await ImagePicker.pickImage(source: source);

    setState(() {
      _image = image;
      faceInfo = null;
    });

    // 如果选取的照片为空，则不执行后续人脸检测的业务逻辑
    if (image == null) {
      return;
    }

    // 调用获取人脸信息的函数
    getFaceInfo(image);
  }

  // 发起请求，获取人脸信息
  void getFaceInfo(image) async {
    setState(() {
      isloading = true;
    });
    // 将照片转换为字节数组
    var imageBytes = await image.readAsBytes();
    // 将字节数组转换为 base64 格式的字符串
    var imageBase64 = base64Encode(imageBytes);

    // 人工智能API接口鉴权
    var accessURL =
        "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=o631j8eLGBQq88uj8IXsVeGO&client_secret=Pses7CgBpF5Hf9owM6N8v8iX6iLAP7G5";
    var accessResult = await dio.post(accessURL);
    // 判断是否获取到了access_token
    if (accessResult.data['access_token'] == null) {
      setState(() {
        isloading = false;
      });
      Toast.show("鉴权失败！", context,
          duration: Toast.LENGTH_LONG, gravity: Toast.CENTER);
      return;
    }

    // 发起请求，获取检测结果
    var testFaceURL =
        'https://aip.baidubce.com/rest/2.0/face/v3/detect?access_token=' +
            accessResult.data['access_token'];
    var testFaceResult = await dio.post(testFaceURL,
        data: {
          'image': imageBase64,
          'image_type': 'BASE64',
          'face_field': 'age,gender,beauty,expression,glasses,emotion'
        },
        options: new Options(contentType: ContentType.json));
    // print(testFaceResult.data);

    // 识别失败
    if (testFaceResult.data['error_msg'] != 'SUCCESS' ||
        testFaceResult.data['result']['face_num'] <= 0) {
      setState(() {
        isloading = false;
      });
      Toast.show("人脸识别失败！", context,
          duration: Toast.LENGTH_LONG, gravity: Toast.CENTER);
      return;
    }

    // 识别成功
    setState(() {
      faceInfo = testFaceResult.data['result']['face_list'][0];
      isloading = false;
    });
    print(faceInfo);
  }
}
